package com.upb.webserver.application;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import com.upb.webserver.common.enums.PlatformEnum;
import com.upb.webserver.common.exception.WebServerException;
import com.upb.webserver.common.returncode.ConstantCode;
import com.upb.webserver.common.tools.JsonUtils;
import com.upb.webserver.common.tools.MybatisExampleTools;
import com.upb.webserver.dao.entity.TbApplication;
import com.upb.webserver.dao.entity.TbApplicationExample;
import com.upb.webserver.dao.entity.TbApplicationOrg;
import com.upb.webserver.dao.entity.TbOrg;
import com.upb.webserver.dao.mapper.TbApplicationMapper;
import com.upb.webserver.dao.mapper.TbApplicationOrgMapper;
import com.upb.webserver.org.OrgManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ApplicationManager {
    @Autowired
    private OrgManager orgManager;
    @Autowired
    private TbApplicationMapper applicationMapper;
    @Autowired
    private TbApplicationOrgMapper applicationOrgMapper;

    /**
     * @param applicationId
     * @return
     */
    public TbApplication verifyApplicationId(int applicationId) {
        log.info("start exec method [verifyApplicationId]. applicationId:{}", applicationId);
        TbApplication application = applicationMapper.selectByPrimaryKey(applicationId);
        if (Objects.isNull(application)) {
            log.warn("fail exec method [verifyApplicationId]. not found record by applicationId:{}", applicationId);
            throw new WebServerException(ConstantCode.APPLICATION_ID_INVALID);
        }
        log.info("success exec method [verifyApplicationId]. applicationId:{}", applicationId);
        return application;
    }

    /**
     * @param appIdList
     * @param status
     * @return
     */
    public long countByApplicationIdListAndStatus(List<Integer> appIdList, byte status) {
        log.info("start exec method [countByApplicationIdListAndStatus] , appIdList:{} status:{}", JsonUtils.objToString(appIdList), status);
        if (CollectionUtil.isEmpty(appIdList)) return 0;
        Map<String, Object> inParam = MapUtil.of("id", appIdList);
        TbApplicationExample example = MybatisExampleTools.initSampleExample(TbApplicationExample.class, new TbApplication(status), inParam);
        long count = applicationMapper.countByExample(example);
        log.info("success exec method [countByApplicationIdListAndStatus] , result:{}", count);
        return count;
    }

    /**
     * @param companyIdList
     * @return
     */
    public Set<Integer> getApplicationIdSetByCompanyIdList(List<Integer> companyIdList) {
        log.info("start exec method [getApplicationIdSetByCompanyId]. companyIdList:{}", JsonUtils.objToString(companyIdList));
        //get orgList by companyId
        List<TbOrg> orgList = orgManager.queryOrgByCompanyIdList(companyIdList);
        if (CollectionUtil.isEmpty(orgList)) {
            log.info("finish exec method [getApplicationIdSetByCompanyId]. not found org by companyIdList:{}", JsonUtils.objToString(companyIdList));
            return CollectionUtil.newHashSet();
        }
        List<Integer> orgIdList = orgList.stream().map(o -> o.getId()).collect(Collectors.toList());

        //get applicationId
        List<TbApplicationOrg> appOrgMapList = applicationOrgMapper.selectByOrgIdList(orgIdList);
        if (CollectionUtil.isEmpty(appOrgMapList)) {
            log.info("finish exec method [getApplicationIdSetByCompanyId]. not found record from tb_application_org by orgIdList:{}", JsonUtils.objToString(orgIdList));
            return CollectionUtil.newHashSet();
        }

        Set<Integer> applicationIdSet = appOrgMapList.stream().map(ao -> ao.getApplicationId()).collect(Collectors.toSet());
        log.info("success exec method [getApplicationIdSetByCompanyId]. result:{}", JsonUtils.objToString(applicationIdSet));
        return applicationIdSet;
    }


    /**
     * @param companyId
     * @return
     */
    public Set<String> getFinalNameByCompanyId(int companyId) {
        log.info("start exec method [getFinalNameByCompanyId]. companyId:{}", companyId);

        Set<String> applicationFinalName = CollectionUtil.emptyIfNull(getApplicationByCompanyIdList(Arrays.asList(companyId))).stream().map(a -> a.getFinalName()).collect(Collectors.toSet());

        log.info("finish exec method [getFinalNameByCompanyId]. companyId:{} result:{}", companyId, JsonUtils.objToString(applicationFinalName));
        return applicationFinalName;
    }


    /**
     * @param companyIdList
     * @return
     */
    public List<TbApplication> getApplicationByCompanyIdList(List<Integer> companyIdList) {
        log.info("start exec method [getApplicationByCompanyId]. companyIdList:{}", JsonUtils.objToString(companyIdList));
        //get orgList by companyId

        if (CollectionUtil.isEmpty(companyIdList))
            return Collections.EMPTY_LIST;

        Set<Integer> applicationIdSet = getApplicationIdSetByCompanyIdList(companyIdList);
        if (CollectionUtil.isEmpty(applicationIdSet))
            return Collections.EMPTY_LIST;

        List<TbApplication> applicationList = getAllApplicationByIdSet(applicationIdSet);

        log.info("success exec method [getApplicationByCompanyId]. result:{}", JsonUtils.objToString(applicationList));
        return applicationList;
    }

    /**
     * @param idSet
     * @return
     */
    public List<TbApplication> getAllApplicationByIdSet(Set<Integer> idSet) {
        log.info("start exec method [getAllApplicationByIdSet]. idSet:{}", JsonUtils.objToString(idSet));
        if (CollectionUtil.isEmpty(idSet)) {
            log.info("finish exec method[getAllApplicationByIdSet], idSet is empty");
            return new ArrayList<>();
        }

        //example
        TbApplicationExample example = new TbApplicationExample();
        TbApplicationExample.Criteria criteria = example.createCriteria();
        criteria.andIdIn(CollectionUtil.newArrayList(idSet));

        // query application list
        List<TbApplication> applicationList = applicationMapper.selectByExampleWithBLOBs(example);
        log.info("success exec method [getAllApplicationByIdSet]. idSet:{} result:{}", JsonUtils.objToString(idSet), JsonUtils.objToString(applicationList));
        return applicationList;
    }

    /**
     * @param platform
     * @param creatorAccountId
     * @return
     */
    public long countApplicationByCreator(PlatformEnum platform, int creatorAccountId) {
        log.debug("start exec method [countApplicationByCreator]. platform:{} creatorAccountId:{}", platform, creatorAccountId);
        TbApplicationExample example = MybatisExampleTools.initSampleExample(TbApplicationExample.class, new TbApplication(platform, creatorAccountId));
        long count = applicationMapper.countByExample(example);
        log.debug("success exec method [countApplicationByCreator]. platform:{} creatorAccountId:{} count:{}", platform, creatorAccountId, count);
        return count;
    }
}
